#pragma once

#include "BasicBlock.hpp"
#include "Type.hpp"
#include "User.hpp"

#include <cassert>
#include <cstddef>
#include <iterator>
#include <list>
#include "ilist.hpp"
#include <map>
#include <memory>

class Module;
class Argument;
class Type;
class FunctionType;

class Function : public Value, public ilist<Function>::node
{
public:
  Function(const Function &) = delete;
  Function(FunctionType *ty, const std::string &name, Module *parent);
  ~Function();
  // 创建并返回函数，参数依次是待创建函数类型 ty，函数名字 name (不可为空)，函数所属的模块 parent
  static Function *create(FunctionType *ty, const std::string &name,
                          Module *parent);

  FunctionType *get_function_type() const; // 返回该函数的函数类型
  Type *get_return_type() const;// 返回该函数的返回值类型

  void add_basic_block(BasicBlock *bb);// 将基本块 bb 添加至该函数末端（调用基本块的创建函数时会自动调用此函数来）

  unsigned get_num_of_args() const;// 得到该函数参数数量
  unsigned get_num_basic_blocks() const;// 得到该函数基本块数量

  Module *get_parent() const;// 得到该函数所属的 Module

  std::list<Argument>::iterator arg_begin() { return arguments_.begin(); }
  std::list<Argument>::iterator arg_end() { return arguments_.end(); }

  void remove(BasicBlock *bb);// 从函数的基本块链表中删除基本块 bb
  BasicBlock *get_entry_block() { return basic_blocks_.empty() ? nullptr : &*basic_blocks_.begin(); }//获取函数入口基本块

  ilist<BasicBlock> &get_basic_blocks() { return basic_blocks_; }// 返回函数基本块链表
  std::list<Argument> &get_args() { return arguments_; }// 返回函数参数链表

  bool is_declaration() { return basic_blocks_.empty(); }//检查当前函数是否只是声明而没有定义

  void set_instr_name();// 给函数中未命名的基本块和指令命名
  std::string print();

private:
  ilist<BasicBlock> basic_blocks_;
  std::list<Argument> arguments_;
  Module *parent_;
  unsigned seq_cnt_; // print use
};

// Argument of Function, does not contain actual value
class Argument : public Value
{
public:
  Argument(const Argument &) = delete;
  explicit Argument(Type *ty, const std::string &name = "",
                    Function *f = nullptr, unsigned arg_no = 0)
      : Value(ty, name), parent_(f), arg_no_(arg_no) {}
  virtual ~Argument() {}
  // 返回参数所属函数
  inline const Function *get_parent() const { return parent_; }
  inline Function *get_parent() { return parent_; }

  /// For example in "void foo(int a, float b)" a is 0 and b is 1.
  unsigned get_arg_no() const // 返回该参数在所在函数的参数列表中的序数
  {
    assert(parent_ && "can't get number of unparented arg");
    return arg_no_;
  }

  virtual std::string print() override;

private:
  Function *parent_;
  unsigned arg_no_; // argument No.
};
